/*
 * Copyright (c) 2017 深圳市高德威技术有限公司  All rights reserved.
 *
 * ctimer.c
 *
 *  Created on: 2017年4月8日
 *      Author: chenshisheng
 */

#include "ctimer.h"
#include "list.h"
#include "utils.h"

#define CTIMER_FLAG_INITIALIZED (0x01)
#define CTIMER_FLAG_STOPED      (0x01 << 1)

struct shot
{
    Ctimer_Callback_t callback;
};

#if 0
// 在链接脚本内定义的内存的BSS段及DATA段的地址范围变量
extern unsigned int  __bss_start__, __bss_end__;
extern unsigned int __data_start__, __data_end__;

#define CSS_START_ADDR (& __bss_start__)
#define CSS_END_ADDR   (& __bss_end__)
#define DATA_START_ADDR (& __data_start__)
#define DATA_END_ADDR  (& __data_end__)


static int _ga = 1;
static int _gb;
#endif

LIST(_list);



void Ctimer_Init(void)
{
#if 0
    static int gc;
    static int gd = 2;
    int la;

    printf("\ncs: %p\nce: %p\nds: %p\nde: %p\nga: %p\ngb: %p\ngc: %p\ngd: %p\nla: %p\n",
            CSS_START_ADDR,
            CSS_END_ADDR,
            & __data_start__,
            & __data_end__,
            & _ga,
            & _gb,
            & gc,
            & gd,
            & la);
#endif

    list_init( _list);
}

void Ctimer_TickUpdate(void)
{
    Ctimer_t *timer;
    struct shot shot;

    for(timer = list_head(_list); timer != NULL; timer = list_item_next(timer))
    {
        if(timer->flags & CTIMER_FLAG_STOPED)
        {
            continue;
        }

        timer->counter += 1;
        if(timer->counter >= timer->interval)
        {
            timer->counter = 0;
            shot.callback = timer->callback;
            MsgQueue_Send(MsgQueue_Id_CtimerFire, & shot, sizeof(shot));
        }
    }
}

void Ctimer_Fire(MsgQueue_Msg_t *msg)
{
    struct shot *pshot;

    pshot = (struct shot *) msg->data;
    pshot->callback();
}

/**
 * @brief 启动一个软件定时器，要求必须使用全局型的定时器变量，
 *        启动后回调函数将被循环触发
 * @param timer 指向全局型的定时器变量
 * @param intervalMs 定时间隔，单位毫秒
 * @param cb    定时到达后被调用的回调函数
 * @param flags 标志集
 * @return 0  启动成功
 *         -1 失败
 */
int Ctimer_Start(Ctimer_t *timer,
        unsigned int intervalMs,
        Ctimer_Callback_t cb,
        unsigned int flags)
{
    if(! Utils_IsGlobalVariable(timer))
    {
        return -1;
    }

    timer->counter = 0;
    timer->interval = intervalMs;
    timer->flags = flags | CTIMER_FLAG_INITIALIZED;
    timer->callback = cb;

    list_add(_list, timer);

    return -1;
}

int Ctimer_Restart(Ctimer_t *timer, unsigned int intervalMs)
{
    if(! (timer->flags & CTIMER_FLAG_INITIALIZED))
    {
        return -1;
    }

    timer->counter = 0;
    timer->interval = intervalMs;
    if(timer->flags & CTIMER_FLAG_STOPED)
    {
        BIT_CLR(timer->flags, CTIMER_FLAG_STOPED);
        list_add(_list, timer);
    }

    return 0;
}

int Ctimer_Reset(Ctimer_t *timer)
{

    if((! (timer->flags & CTIMER_FLAG_INITIALIZED)) ||
            (timer->flags & CTIMER_FLAG_STOPED))
    {
        return -1;
    }

    timer->counter = 0;

    return 0;
}

int Ctimer_Stop(Ctimer_t *timer)
{
    if(!(timer->flags & CTIMER_FLAG_INITIALIZED))
    {
        return -1;
    }

    list_remove(_list, timer);
    BIT_SET(timer->flags, CTIMER_FLAG_STOPED);

    return 0;
}

int Ctimer_IsRunning(Ctimer_t *timer)
{
    return (timer->flags & CTIMER_FLAG_INITIALIZED) &&
            ! (timer->flags & CTIMER_FLAG_STOPED);
}

unsigned int Ctimer_Interval(Ctimer_t *timer)
{
    return timer->interval;
}
